package io.github.xbeeant.eoffice.service.impl;

import io.github.xbeeant.core.ApiResponse;
import io.github.xbeeant.core.IdWorker;
import io.github.xbeeant.core.JsonHelper;
import io.github.xbeeant.eoffice.config.AbstractSecurityMybatisPageHelperServiceImpl;
import io.github.xbeeant.eoffice.mapper.AttachmentMapper;
import io.github.xbeeant.eoffice.model.Attachment;
import io.github.xbeeant.eoffice.model.Resources;
import io.github.xbeeant.eoffice.model.ResourcesVersion;
import io.github.xbeeant.eoffice.onlyoffice.OnlyOfficeCallback;
import io.github.xbeeant.eoffice.onlyoffice.OnlyOfficeConfiguration;
import io.github.xbeeant.eoffice.service.IAttachmentService;
import io.github.xbeeant.eoffice.service.IResourcesService;
import io.github.xbeeant.eoffice.service.IResourcesVersionService;
import io.github.xbeeant.eoffice.util.FileHelper;
import io.github.xbeeant.eoffice.util.UrlHelper;
import io.github.xbeeant.spring.mybatis.pagehelper.IMybatisPageHelperDao;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.NoSuchAlgorithmException;

/**
 * 文档
 */
@Service
public class AttachmentServiceImpl extends AbstractSecurityMybatisPageHelperServiceImpl<Attachment, Long> implements IAttachmentService {

    private static final Logger logger = LoggerFactory.getLogger(AttachmentServiceImpl.class);

    @Autowired
    private AttachmentMapper attachmentMapper;

    @Autowired
    private OnlyOfficeConfiguration onlyOfficeConfiguration;

    @Autowired
    private IResourcesService resourcesService;

    @Autowired
    private IResourcesVersionService resourcesVersionService;

    @Override
    public IMybatisPageHelperDao<Attachment, Long> getRepositoryDao() {
        return this.attachmentMapper;
    }

    @Override
    public void setDefaults(Attachment record) {
        if (record.getAid() == null) {
            record.setAid(IdWorker.getId());
        }
    }

    @Override
    public Attachment save(MultipartFile file, String userId) throws IOException, NoSuchAlgorithmException {
        String filename = file.getOriginalFilename();
        long fileSize = file.getSize();
        String type = FileHelper.extension(filename);
        String md5 = FileHelper.md5(file);
        // MD5比较，如果文件已经存在，直接返回已经存在的文件信息，避免重复存储
        Attachment example = new Attachment();
        example.setMd5(md5);
        ApiResponse<Attachment> attachmentApiResponse = selectOneByExample(example);
        Attachment attachment;
        if (!attachmentApiResponse.getSuccess()) {
            long aid = IdWorker.getId();
            String storageName = aid + "_" + md5 + "." + type;
            String fileStoragePath = onlyOfficeConfiguration.getStorageFolder() + storageName;
            if (logger.isInfoEnabled()) {
                logger.info("开始保存文档 {} 存储路径 {}", userId, fileStoragePath);
            }
            File storageFile = new File(fileStoragePath);
            // 保存
            file.transferTo(storageFile);

            // save to database
            // 写入数据库
            attachment = new Attachment();
            attachment.setMd5(md5);
            attachment.setFileSize(fileSize);
            attachment.setFileType(type);
            attachment.setAttachment(storageName);
            attachment.setFilename(filename);
            attachment.setCreateBy(userId);
            attachment.setUpdateBy(userId);
            insertSelective(attachment);
        } else {
            attachment = attachmentApiResponse.getData();
        }
        return attachment;
    }

    @Override
    public boolean save(OnlyOfficeCallback callback, String userId) {
        String url = callback.getUrl();
        String documentKey = callback.getKey();
        String changesUrl = callback.getChangesurl();
        UrlHelper.UrlEntity parse = UrlHelper.parse(url);
        String filename = parse.params.get("filename");
        String md5 = parse.params.get("md5");
        String type = filename.substring(filename.indexOf("."));
        // 项目打包成jar包所在的根路径
        String storageName = documentKey + type;
        String fileStoragePath = onlyOfficeConfiguration.getStorageFolder() + storageName;
        File storageFile = new File(fileStoragePath);
        boolean success = false;
        if (logger.isInfoEnabled()) {
            logger.info("开始保存文档 {} {} {} 存储路径 {}", documentKey, userId, url, fileStoragePath);
        }
        try {
            FileUtils.copyURLToFile(new URL(url), storageFile);
            if (storageFile.exists() && storageFile.length() > 0) {
                success = true;
            }
        } catch (IOException e) {
            logger.error("$$$ 保存文档失败！", e);
        }
        String[] keys = documentKey.split("_");
        Long lRid = Long.valueOf(keys[0]);
        ApiResponse<Resources> resourcesApiResponse = resourcesService.selectByPrimaryKey(lRid);
        Resources resource = resourcesApiResponse.getData();

        // 保存变更历史信息
        String changes = saveHistory(documentKey, changesUrl);

        // 写入数据库
        Attachment file = new Attachment();
        file.setFileType(type);
        file.setMd5(md5);
        file.setFileSize(storageFile.length());
        file.setAttachment(storageName);
        file.setFilename(resource.getName() + "." + type);
        file.setCreateBy(userId);
        file.setUpdateBy(userId);
        insertSelective(file);
        // 记录资源和附件的关系
        ResourcesVersion resourcesVersion = new ResourcesVersion();
        resourcesVersion.setRid(lRid);
        resourcesVersion.setAid(file.getAid());
        resourcesVersion.setSize(file.getFileSize());
        resourcesVersion.setType(file.getFileType());
        resourcesVersion.setVname(resource.getName());
        resourcesVersion.setType(resource.getType());
        resourcesVersion.setCreateBy(userId);
        resourcesVersion.setUpdateBy(userId);
        if (null != callback.getHistory()) {
            resourcesVersion.setServerVersion(callback.getHistory().getServerVersion());
            resourcesVersion.setChanges(JsonHelper.toJsonString(callback.getHistory().getChanges()));
        }
        resourcesVersion.setAttachment(changes);
        resourcesVersionService.insertSelective(resourcesVersion);
        // 更新资源的文件信息
        Resources resources = new Resources();
        resources.setRid(lRid);
        resources.setSize(file.getFileSize());
        resourcesService.updateByPrimaryKeySelective(resources);


        return success;
    }

    private String saveHistory(String documentKey, String changesurl) {
        if (null == changesurl) {
            return null;
        }

        UrlHelper.UrlEntity parse = UrlHelper.parse(changesurl);
        String filename = parse.params.get("filename");
        String type = filename.substring(filename.indexOf("."));
        // 项目打包成jar包所在的根路径
        String storageName = documentKey + type;
        String fileStoragePath = onlyOfficeConfiguration.getChangesFolder() + storageName;
        File storageFile = new File(fileStoragePath);

        if (logger.isInfoEnabled()) {
            logger.info("开始保存文档 {} {} 存储路径 {}", documentKey, changesurl, fileStoragePath);
        }
        try {
            FileUtils.copyURLToFile(new URL(changesurl), storageFile);
        } catch (IOException e) {
            logger.error("$$$ 保存文档失败！", e);
            return null;
        }
        return storageName;
    }
}
